#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "iic.h"
#define SCL       0
#define SDA       1
#define GPIO_INPUT_PIN_SEL  (1ULL<<SDA)
#define GPIO_OUTPUT_PIN_SEL  ((1ULL<<SCL) | (1ULL<<SDA))
#define SCL_H          gpio_set_level(SCL,1)
#define SCL_L          gpio_set_level(SCL,0)
#define SDA_H         gpio_set_level(SDA,1)
#define SDA_L         gpio_set_level(SDA,0)
#define READ_SDA      gpio_get_level(SDA)
#define delay_ms(time)       vTaskDelay(time / portTICK_RATE_MS)
void SDA_OUT(void)
{
    //zero-initialize the config structure.
    gpio_config_t io_conf = {};
    //disable interrupt
    io_conf.intr_type = GPIO_INTR_DISABLE;
    //set as output mode
    io_conf.mode = GPIO_MODE_OUTPUT;
    //bit mask of the pins that you want to set,e.g.GPIO18/19
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    //disable pull-up mode
    io_conf.pull_up_en = 0;
    //configure GPIO with the given settings
    gpio_config(&io_conf);
}
 void SDA_IN(void)
{
       //zero-initialize the config structure.
    gpio_config_t io_conf = {};
    //disable interrupt
    io_conf.intr_type = GPIO_INTR_DISABLE;
    //set as output mode
    io_conf.mode = GPIO_MODE_INPUT;
    //bit mask of the pins that you want to set,e.g.GPIO18/19
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    //disable pull-up mode
    io_conf.pull_up_en = 0;
    //configure GPIO with the given settings
    gpio_config(&io_conf);
}
//初始化IIC
void  mx_iic_init(void)
{ 
    //zero-initialize the config structure.
    gpio_config_t io_conf = {};
    //disable interrupt
    io_conf.intr_type = GPIO_INTR_DISABLE;
    //set as output mode
    io_conf.mode = GPIO_MODE_OUTPUT;
    //bit mask of the pins that you want to set,e.g.GPIO18/19
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    //disable pull-up mode
    io_conf.pull_up_en = 0;
    //configure GPIO with the given settings
    gpio_config(&io_conf);
}
//产生IIC起始信号
void IIC_Start(void)
{
  SDA_OUT();     //sda线输出
  SDA_H;        
  SCL_H;
  delay_ms(10);
  SDA_L;//START:when CLK is high,DATA change form high to low 
  delay_ms(10);
  SCL_L;//钳住I2C总线，准备发送或接收数据 
}	  
//产生IIC停止信号
void IIC_Stop(void)
{
	SDA_OUT();//sda线输出
    //delay_ms(4);
	SCL_L;
	SDA_L;//STOP:when CLK is high DATA change form low to high
 	delay_ms(4);
	SCL_H; 
	SDA_H;//发送I2C总线结束信号
	delay_ms(4);	
						   	
}
//等待应答信号到来
//返回值：1，接收应答失败
//        0，接收应答成功
uint8_t IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	SDA_IN();      //SDA设置为输入 
    //delay_ms(2); //2MS延时测试ACK成功，20ms失败
	//SDA_H;delay_ms(1);	-----------------------------------------!   
	SCL_H;
    delay_ms(2); //2ms延时测试ACK成功	 
	while(READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	   
	return 0;  
} 
//等待应答信号到来
//返回值：1，接收应答失败
//        0，接收应答成功
//经测试两次设置SDA为输入时，SDA会变成输出！！！
uint8_t IIC_Wait_Ack2(void)
{
	u8 ucErrTime=0;
	SDA_IN();      //SDA设置为输入  
	//SDA_H;delay_ms(1);	-----------------------------------------!   
	SCL_H;	
    delay_us(1);
	while(READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	SCL_L;//时钟输出0 	   
	return 0;  
} 
void delay_us(u16 Count)
{
  u8 i,j;
  while (Count--)//Count形参控制延时次数
  {
    for(i=0;i<10;i++)
      for(j=0;j<20;j++);
  }
}
//产生ACK应答
void IIC_Ack(void)
{
	SCL_L;
	SDA_OUT();
	SDA_L;
	delay_ms(10);
	SCL_H;
	delay_ms(10);
	SCL_L;
}
//不产生ACK应答		    
void IIC_NAck(void)
{
	SCL_L;
	SDA_OUT();
	SDA_H;
	delay_ms(2);
	SCL_H;
	delay_ms(2);
	SCL_L;
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1，有应答
//0，无应答			  
void IIC_Send_Byte(uint8_t txd)
{                        
    u8 t;   
	SDA_OUT(); 	    
    SCL_L;//拉低时钟开始数据传输,后面不加延时，否则设置寄存器指针的第二个ACK返回1
    for(t=0;t<8;t++)
    {              
        //IIC_SDA=(txd&0x80)>>7;
		if((txd&0x80)>>7)
			SDA_H;
		else
			SDA_L;
		txd<<=1; 	  
		//delay_ms(2);   //对TEA5767这三个延时都是必须的
		SCL_H;
		delay_us(1); 
		SCL_L;	
        delay_us(1);
    }	 
} 	    
//读1个字节，ack=1时，发送ACK，ack=0，发送nACK   
u8 IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        SCL_L; 
        delay_ms(1);
		SCL_H;
        receive<<=1;
        if(READ_SDA)
        {
             receive++;
            // printf("读取到SDA = 1 \n");
        }
          
		delay_ms(1); 
    }					 
    if (!ack)
        IIC_NAck();//如果是读取第二个字节，master发送nACK（即发送高电平1）
    else
        IIC_Ack(); //如果读取第一个字节，master发送ACK（即发送低电平0）  
    return receive;
}



























